/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package proyectoia;

import aima.search.framework.Successor;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Set;

/**
 *
 * @author brian.carvajal
 */
public class DistFileSystemSuccessorFunctionSA1 extends DistFileSystemSuccessorFunction {
    
    private  Random random;
    
     DistFileSystemSuccessorFunctionSA1() {
        super();
        random = new Random(0);
    }
     
    private Integer getRandomAsignedRequest(DistFileSystemState state, Integer server) {
       // System.out.println("\n###########################################");
        return random.nextInt(state.allocations.get(server).size());
    }
    
    private List doSwap(DistFileSystemState state) {
        ArrayList sucs = new ArrayList();

        
        DistFileSystemState newState = new DistFileSystemState(state);
        Integer sMax,s2,req1,req2;
        
        sMax = state.getSlowestServer();
        
        //copiamos las peticiones asignados a sMax
        ArrayList<Integer> requests1 = new ArrayList();
        for (Integer req : state.allocations.get(sMax)) {
            requests1.add(req);
        }
        
        //iteramos hasta encontrar una combinacion correcta
        do {
            //seleccionamos una request asignada al azar y la eliminamos de la lista
            req1 = requests1.get(random.nextInt(requests1.size()));
            requests1.remove(req1);
            
            //copiamos los servidores donde se puede asignar la peticion seleccionada
            ArrayList<Integer> servers2 = new ArrayList();
            for (Integer server : state.getFileLocations(state.getFile(req1))) {
                servers2.add(server);
            }
            
            //eliminamos sMax de la lista
            servers2.remove(sMax);
            
            //iteramos hasta encontrar un servidor que nos sirva
            do {
                //seleccionamos un server al azar
                s2 = servers2.get(random.nextInt(servers2.size()));
                servers2.remove(s2);
                
                //copiamos las peticiones asignadas a s2
                ArrayList<Integer> requests2 = new ArrayList();
                for (Integer req : state.allocations.get(s2)) {
                    requests2.add(req);
                }
                
                //seleccionamos una peticion de s2 al azar          
                do {
                    req2 = requests2.get(random.nextInt(requests2.size()));
                    requests2.remove(req2);
                    
                }while(!requests2.isEmpty() && !state.getFileLocations(state.getFile(req2)).contains(sMax));
                
            } while(!servers2.isEmpty());          
        }while(!state.isAllocatable(req1, s2) && !state.isAllocatable(req2, sMax));
      //  System.out.println("Swaping reqs "+req1+" and "+req2+" between ss "+sMax+" and "+s2);
        String operation = newState.swapAllocationsOperator(req1, req2, sMax, s2);
        if (operation.equals("nop")) System.out.println("Invalid Swap");
        sucs.add(new Successor(operation, newState));
        return sucs;
    }
    
    private List doChange(DistFileSystemState state) {
                ArrayList sucs = new ArrayList();

        
        DistFileSystemState newState = new DistFileSystemState(state);
        Integer sMax,s2,req1;
        
        sMax = state.getSlowestServer();
        
        //copiamos las peticiones asignados a sMax
        ArrayList<Integer> requests1 = new ArrayList();
        for (Integer req : state.allocations.get(sMax)) {
            requests1.add(req);
        }
        
        //iteramos hasta encontrar una combinacion correcta
        do {
            //seleccionamos una request asignada al azar y la eliminamos de la lista
            req1 = requests1.get(random.nextInt(requests1.size()));
            requests1.remove(req1);
            
            //copiamos los servidores donde se puede asignar la peticion seleccionada
            ArrayList<Integer> servers2 = new ArrayList();
            for (Integer server : state.getFileLocations(state.getFile(req1))) {
                servers2.add(server);
            }
            
            //eliminamos sMax de la lista
            servers2.remove(sMax);
            
            
            //seleccionamos un server al azar
            s2 = servers2.get(random.nextInt(servers2.size()));
            servers2.remove(s2);
    
        }while(!state.isAllocatable(req1, s2));
        
        //System.out.println("Changing file="+state.getFile(req1) +" from s="+sMax+" to s="+s2);
        String operation = newState.changeAllocationOperator(req1, sMax, s2);
        if (operation.equals("nop")) System.out.println("Invalid Change");
        sucs.add(new Successor(operation, newState));
        return sucs;
    }
     
     @Override
    public List getSuccessors(Object s) {
        super.getSuccessors(s);
        DistFileSystemState state = (DistFileSystemState) s;
        Integer op = random.nextInt(2);
        

        List sucs = null;
        switch (op) {
            case 0: 
                sucs = doChange(state);
                if (sucs.isEmpty()) sucs = doSwap(state); 
                break;
            case 1: 
                sucs = doSwap(state); 
                 if (sucs.isEmpty()) sucs = doChange(state); 
                break;
        } 
        return sucs;
     }
        
        
        
       
        

//        System.out.println("\n###########################################");
//        sMax = state.getSlowestServer();
//        System.out.println("Smax: "+sMax);
//        do {
//            System.out.println("Searching req1...");
//            req1 = getRandomAsignedRequest(state, sMax);
//            System.out.println("    req1: "+req1);
//            Integer[] servers = new Integer[0];
//            servers = state.getFileLocations(state.getFile(req1)).toArray(servers);
//            do {
//                System.out.println("    Searching s2...");
//                s2 = random.nextInt(servers.length);
//                System.out.println("        s2: "+s2);
//            } while (s2.equals(sMax));      
//            req2 = getRandomAsignedRequest(state, s2);
//            System.out.println("    req2: "+req2);
//            if (!state.isAllocatable(req2, sMax)) System.out.println("req="+req2+" no se puede asignar a s="+sMax);
//        } while (!state.isAllocatable(req2, sMax));
// 
//        Integer op = random.nextInt(2);
//        String operation;
//        switch (op) {
//            case 0:
//                System.out.println("Changing file="+state.getFile(req1) +" from s="+sMax+" to s="+s2);
//                
//                operation = newState.changeAllocationOperator(req1, sMax, s2);
//                if (operation.equals("nop")) System.out.println("Invalid Change");
//                sucs.add(new Successor(operation, newState));
//                break;
//            case 1:
//                System.out.println("Swaping reqs "+req1+" and "+req2+" between ss "+sMax+" and "+s2);
//                operation = newState.swapAllocationsOperator(req1, req2, sMax, s2);
//                if (operation.equals("nop")) System.out.println("Invalid Swap");
//                sucs.add(new Successor(operation, newState));
//                break;
//        }
//        state.printAllocations();
//        state.print();
//        return sucs;
//    }
     
    @Override
    public String toString() {
        return "Cambiar e intercambiar";
    }
}
